---
category: Advanced
title: Custom Abstractions
order: 1
---

A lot of the components you will find in the package
[@threlte/extras](/docs/reference/extras/getting-started) are abstractions on
top of the [`<T>` component](/docs/reference/core/t). These abstractions provide
extra functionality like automatically invalidating the frame or providing
default values or extra props.

A common use case for custom abstractions is to create a component that is a
fixed entity in your Threlte app which you want to reuse in multiple places or
which exposes a specific behavior. As an example, let's create a component that
is made up from multiple `<T>` components resembling a tile of some kind:

```svelte title="Tile.svelte"
<script>
  import { T } from '@threlte/threlte'
  import { MathUtils } from 'three'

  let { children } = $props()
</script>

<T.Group>
  <!-- 2x2 Tile -->
  <T.Mesh rotation.x={-90 * MathUtils.DEG2RAD}>
    <T.PlaneGeometry args={[2, 2]} />
    <T.MeshStandardMaterial />
  </T.Mesh>

  {@render children()}
</T.Group>
```

Let's see what implementing that component looks like:

```svelte title="Scene.svelte"
<script>
  import Tile from './Tile.svelte'
</script>

<Tile />
```

## Props

The `<Tile>` component is now available in the scene and can be reused as many
times as you want.

Now we'd like to assign a different `position` to every `<Tile>` in order to
position it in the scene. We can do that by passing a `position` prop to the
`<Tile>` component:

```svelte title="Scene.svelte"
<script>
  import Tile from './Tile.svelte'
</script>

<Tile position={[0, 0, 0]} />
<Tile position={[2, 0, 0]} />
<Tile position={[4, 0, 0]} />
```

That doesn't work _yet_. The component `<Tile>` internally needs to make use of
the `position` prop to set the position of its children. We can do that by
[spreading `rest` on the `<T.Group>`](https://svelte.dev/docs/svelte/$props#Rest-props)
component at the root hierarchy of `<Tile>`:

```svelte title="Tile.svelte" {5}m
<script>
  import { T } from '@threlte/threlte'
  import { MathUtils } from 'three'

  let { children, ...props } = $props()
</script>

<T.Group {...props}>
  <!-- 2x2 Floor -->
  <T.Mesh rotation.x={-90 * MathUtils.DEG2RAD}>
    <T.PlaneGeometry args={[2, 2]} />
    <T.MeshStandardMaterial />
  </T.Mesh>

  {@render children()}
</T.Group>
```

## Types

<Tip type="info">The following section assumes you use TypeScript.</Tip>

The last thing we need to do is to add types to our custom abstraction so that
IDEs like VS Code can provide autocompletion and type checking. We will create a
`types.ts` file next to the `Tile.svelte` file and add the following content:

```ts title="types.ts"
import type { Props } from '@threlte/core'
import type { Group } from 'three'

export type TileProps = Props<Group>
```

<Tip type="tip">
  As of now it's necessary to declare the props in a separate file.
	If you declare them inside the `<script>` block, the Svelte compiler
	flattens the resulting type, removing JSDoc comments and possibly
	breaking it.
</Tip>

The generic type `Props<Type>` is a utility type that extracts all possible
props that a `<T>` component accepts – in this case `<T.Group>`. It also creates
a _bindable `ref` prop_ that can be used to bind to the group created by the
`<T.Group>` component.

We need to import the `TileProps` type in our `Tile.svelte` file and make use of
the `ref` prop. For that we:

- Add the `lang="ts"` attribute to the `<script>` block
- Import the `TileProps` type
- Add the bindable prop `ref` to the props
- Bind `ref` to the bindable prop `ref` of the root `<T.Group>` component
- Pass `ref` to the `children()` block

```svelte title="Tile.svelte" {4,11}+ {1,6,19}m
<script lang="ts">
  import { T } from '@threlte/threlte'
  import { MathUtils } from 'three'
  import type { TileProps } from './types'

  let { children, ref = $bindable(), ...props }: TileProps = $props()
</script>

<T.Group
  {...props}
  bind:ref
>
  <!-- 2x2 Floor -->
  <T.Mesh rotation.x={-90 * MathUtils.DEG2RAD}>
    <T.PlaneGeometry args={[2, 2]} />
    <T.MeshStandardMaterial />
  </T.Mesh>

  {@render children({ ref })}
</T.Group>
```

Now we can use the `<Tile>` component in our scene and get autocompletion and
type checking.

```svelte title="Scene.svelte"
<script>
  import Tile from './Tile.svelte'
  import { TransformControls } from '@threlte/extras'
</script>

<Tile position={[2, 0, 2]}>
  {#snippet children({ ref })}
    <TransformControls object={ref} />
  {/snippet}
</Tile>
```
